Layer* SpaceCreateLayers(CNN *cnn)
{
	int i;
	cnn->Layers = (Layer*)malloc((cnn->HiddenLayerNum + 2) * sizeof(Layer));
	for (i = 0; i < cnn->HiddenLayerNum + 2; i++)
	{
		InitLayer(&cnn->Layers[i]);
	}
	return cnn->Layers;
}

int LoadinPara2Layers(CNN *cnn, Predefine pdf)
{
	//Input
	cnn->Layers[0].OutSize[0] = cnn->SampleCha;
	cnn->Layers[0].OutSize[1] = cnn->SampleRow;
	cnn->Layers[0].OutSize[2] = cnn->SampleCol;
	int cnt = 0;
	int i;
	for (i = 1; i < cnn->HiddenLayerNum + 2; i++)
	{
		if (pdf.LayerType[i] == 0)			//F:oa
		{
			cnn->Layers[i].LayerType = 0;
			cnn->Layers[i].OutSize[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].ActiFuncNum = pdf.LayerParameters[cnt]; cnt = cnt + 1;

			cnn->Layers[i].OutSize[1] = 1;
			cnn->Layers[i].OutSize[2] = 1;
		}
		else if (pdf.LayerType[i] == 1)		//C:PKSOA
		{
			cnn->Layers[i].LayerType = 1;
			cnn->Layers[i].PaddingMode = pdf.LayerParameters[cnt];cnt = cnt + 1;
			cnn->Layers[i].KernelSize[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].KernelSize[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].OutSize[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].ActiFuncNum = pdf.LayerParameters[cnt]; cnt = cnt + 1;

			if (cnn->Layers[i].PaddingMode == 0) 
			{
				cnn->Layers[i].OutSize[1] = (cnn->Layers[i - 1].OutSize[1] + cnn->Layers[i].Stride[0] 
					- cnn->Layers[i].KernelSize[0]) / cnn->Layers[i].Stride[0];
				cnn->Layers[i].OutSize[2] = (cnn->Layers[i - 1].OutSize[2] + cnn->Layers[i].Stride[1]
					- cnn->Layers[i].KernelSize[1]) / cnn->Layers[i].Stride[1];
			}
			else {
				cnn->Layers[i].OutSize[1] = (cnn->Layers[i - 1].OutSize[1] + 
					cnn->Layers[i].Stride[0] - 1) / cnn->Layers[i].Stride[0];
				cnn->Layers[i].OutSize[2] = (cnn->Layers[i - 1].OutSize[2] + 
					cnn->Layers[i].Stride[1] - 1) / cnn->Layers[i].Stride[1];
			}
		}
		else if (pdf.LayerType[i] == 2)		//deC:PKSOA
		{
			cnn->Layers[i].LayerType = 2;
			cnn->Layers[i].PaddingMode = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].KernelSize[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].KernelSize[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].OutSize[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].ActiFuncNum = pdf.LayerParameters[cnt]; cnt = cnt + 1;

			cnn->Layers[i].OutSize[1] = (cnn->Layers[i - 1].OutSize[1] - 1)*
				cnn->Layers[i].Stride[0] + cnn->Layers[i].KernelSize[0];
			cnn->Layers[i].OutSize[2] = (cnn->Layers[i - 1].OutSize[2] - 1)*
				cnn->Layers[i].Stride[1] + cnn->Layers[i].KernelSize[1];
		}
		else if (pdf.LayerType[i] == 3)		//mp:PKS
		{
			cnn->Layers[i].LayerType = 3;
			cnn->Layers[i].PaddingMode = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].KernelSize[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].KernelSize[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;

			cnn->Layers[i].OutSize[0] = cnn->Layers[i - 1].OutSize[0];
			if (cnn->Layers[i].PaddingMode == 0)
			{
				cnn->Layers[i].OutSize[1] = (cnn->Layers[i - 1].OutSize[1] + cnn->Layers[i].Stride[0]
					- cnn->Layers[i].KernelSize[0]) / cnn->Layers[i].Stride[0];
				cnn->Layers[i].OutSize[2] = (cnn->Layers[i - 1].OutSize[2] + cnn->Layers[i].Stride[1]
					- cnn->Layers[i].KernelSize[1]) / cnn->Layers[i].Stride[1];
			}
			else {
				cnn->Layers[i].OutSize[1] = (cnn->Layers[i - 1].OutSize[1] +
					cnn->Layers[i].Stride[0] - 1) / cnn->Layers[i].Stride[0];
				cnn->Layers[i].OutSize[2] = (cnn->Layers[i - 1].OutSize[2] +
					cnn->Layers[i].Stride[1] - 1) / cnn->Layers[i].Stride[1];
			}
		}
		else if (pdf.LayerType[i] == 4)		//ap
		{
			cnn->Layers[i].LayerType = 4;
			cnn->Layers[i].PaddingMode = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].KernelSize[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].KernelSize[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[0] = pdf.LayerParameters[cnt]; cnt = cnt + 1;
			cnn->Layers[i].Stride[1] = pdf.LayerParameters[cnt]; cnt = cnt + 1;

			cnn->Layers[i].OutSize[0] = cnn->Layers[i - 1].OutSize[0];
			if (cnn->Layers[i].PaddingMode == 0)
			{
				cnn->Layers[i].OutSize[1] = (cnn->Layers[i - 1].OutSize[1] + cnn->Layers[i].Stride[0]
					- cnn->Layers[i].KernelSize[0]) / cnn->Layers[i].Stride[0];
				cnn->Layers[i].OutSize[2] = (cnn->Layers[i - 1].OutSize[2] + cnn->Layers[i].Stride[1]
					- cnn->Layers[i].KernelSize[1]) / cnn->Layers[i].Stride[1];
			}
			else {
				cnn->Layers[i].OutSize[1] = (cnn->Layers[i - 1].OutSize[1] +
					cnn->Layers[i].Stride[0] - 1) / cnn->Layers[i].Stride[0];
				cnn->Layers[i].OutSize[2] = (cnn->Layers[i - 1].OutSize[2] +
					cnn->Layers[i].Stride[1] - 1) / cnn->Layers[i].Stride[1];
			}
		}
		else {
			return -1;
		}
	}
	return 0;
}
// now CHW while should be  HWC
Layer* SpaceCreateInputLayer(Layer *input)
{
	int i;
	input->ActiMat = (Mat*)malloc(input->OutSize[0] * sizeof(Mat));
	for (i = 0; i < input->OutSize[0]; ++i)
	{
		MatCreate(&input->ActiMat[i], input->OutSize[1], input->OutSize[2]);
	}
	return input;
}

Layer* SpaceCreateFullConnLayer(Layer *fc,int InSize[3])
{
	fc->OriginMat = (Mat*)malloc(sizeof(Mat));
	MatCreate(fc->OriginMat, 1
		, InSize[0] * InSize[1] * InSize[2] + 1);
	MatCreate(&fc->KernelMat, InSize[0] * InSize[1] * InSize[2], fc->OutSize[0]);
	MatCreate(&fc->WeightMat, InSize[0] * InSize[1] * InSize[2] + 1, fc->OutSize[0]);
	MatCreate(&fc->NablaMat, InSize[0] * InSize[1] * InSize[2] + 1, fc->OutSize[0]);
	fc->SumMat = (Mat*)malloc(sizeof(Mat));
	MatCreate(fc->SumMat, 1, fc->OutSize[0]);
	fc->ActiMat = (Mat*)malloc(sizeof(Mat));
	MatCreate(fc->ActiMat, 1, fc->OutSize[0]);
	fc->DeriMat = (Mat*)malloc(sizeof(Mat));
	MatCreate(fc->DeriMat, 1, fc->OutSize[0]);
	fc->DeltaMat = (Mat*)malloc(sizeof(Mat));
	MatCreate(fc->DeltaMat, 1, fc->OutSize[0]);
	return fc;
}

Layer* SpaceCreateConvLayer(Layer *cv, int InSize[3])
{
	int i;
	MatCreate(&cv->KernelMat, cv->KernelSize[0] * cv->KernelSize[1] * InSize[0], cv->OutSize[0]);
	MatCreate(&cv->WeightMat, cv->KernelSize[0] * cv->KernelSize[1] * InSize[0] + 1, cv->OutSize[0]);
	MatCreate(&cv->NablaMat, cv->KernelSize[0] * cv->KernelSize[1] * InSize[0] + 1, cv->OutSize[0]);
	cv->OriginMat = (Mat*)malloc((cv->KernelSize[0] * cv->KernelSize[1] * InSize[0] + 1) * sizeof(Mat));
	for (i = 0; i < cv->KernelSize[0] * cv->KernelSize[1] * InSize[0] +1; ++i)
	{
		MatCreate(&cv->OriginMat[i], cv->OutSize[1], cv->OutSize[2]);
	}
	cv->SumMat = (Mat*)malloc(cv->OutSize[0] * sizeof(Mat));
	cv->ActiMat = (Mat*)malloc(cv->OutSize[0] * sizeof(Mat));
	cv->DeriMat = (Mat*)malloc(cv->OutSize[0] * sizeof(Mat));
	cv->DeltaMat = (Mat*)malloc(cv->OutSize[0] * sizeof(Mat));
	for (i = 0; i < cv->OutSize[0]; ++i)
	{
		MatCreate(&cv->SumMat[i], cv->OutSize[1], cv->OutSize[2]);
		MatCreate(&cv->ActiMat[i], cv->OutSize[1], cv->OutSize[2]);
		MatCreate(&cv->DeriMat[i], cv->OutSize[1], cv->OutSize[2]);
		MatCreate(&cv->DeltaMat[i], cv->OutSize[1], cv->OutSize[2]);
	}
	return cv;
}

Layer* SpaceCreateDeConvLayer(Layer *dec, int InSize[3])
{
	int i;
	MatCreate(&dec->KernelMat, InSize[0], dec->KernelSize[0] * dec->KernelSize[1] * dec->OutSize[0]);
	MatCreate(&dec->NablaMat, InSize[0], dec->KernelSize[0] * dec->KernelSize[1] * dec->OutSize[0]);
	dec->OriginMat = (Mat*)malloc(dec->KernelSize[0] * dec->KernelSize[1] * dec->OutSize[0] * sizeof(Mat));
	for (i = 0; i < dec->KernelSize[0] * dec->KernelSize[1] * dec->OutSize[0]; ++i)
	{
		MatCreate(&dec->OriginMat[i], InSize[1], InSize[2]);
	}
	dec->SumMat = (Mat*)malloc(dec->OutSize[0] * sizeof(Mat));
	dec->ActiMat = (Mat*)malloc(dec->OutSize[0] * sizeof(Mat));
	dec->DeriMat = (Mat*)malloc(dec->OutSize[0] * sizeof(Mat));
	dec->DeltaMat = (Mat*)malloc(dec->OutSize[0] * sizeof(Mat));
	for (i = 0; i < dec->OutSize[0]; ++i)
	{
		MatCreate(&dec->SumMat[i], dec->OutSize[1], dec->OutSize[2]);
		MatCreate(&dec->ActiMat[i], dec->OutSize[1], dec->OutSize[2]);
		MatCreate(&dec->DeriMat[i], dec->OutSize[1], dec->OutSize[2]);
		MatCreate(&dec->DeltaMat[i], dec->OutSize[1], dec->OutSize[2]);
	}
	return dec;
}

Layer* SpaceCreateMaxPoolLayer(Layer *mp, int InSize[3])
{
	int i;
	mp->OriginMat = (Mat*)malloc(mp->KernelSize[0] * mp->KernelSize[1] * InSize[0] * sizeof(Mat));
	for (i = 0; i < mp->KernelSize[0] * mp->KernelSize[1] * InSize[0]; ++i)
	{
		MatCreate(&mp->OriginMat[i], mp->OutSize[1], mp->OutSize[2]);
	}
	MatCreate(&mp->KernelMat, mp->OutSize[1] * mp->OutSize[2], mp->OutSize[0]);
	mp->ActiMat = (Mat*)malloc(mp->OutSize[0] * sizeof(Mat));
	mp->DeltaMat = (Mat*)malloc(mp->OutSize[0] * sizeof(Mat));
	for (i = 0; i < mp->OutSize[0]; ++i)
	{
		MatCreate(&mp->ActiMat[i], mp->OutSize[1], mp->OutSize[2]);
		MatCreate(&mp->DeltaMat[i], mp->OutSize[1], mp->OutSize[2]);
	}
	return mp;
}

Layer* SpaceCreateAvePoolLayer(Layer *ap, int InSize[3])
{
	int i;
	MatCreate(&ap->KernelMat, ap->KernelSize[0] * ap->KernelSize[1] * InSize[0], ap->OutSize[0]);
	ap->OriginMat = (Mat*)malloc(ap->KernelSize[0] * ap->KernelSize[1] * InSize[0] * sizeof(Mat));
	for (i = 0; i < ap->KernelSize[0] * ap->KernelSize[1] * InSize[0]; ++i)
	{
		MatCreate(&ap->OriginMat[i], ap->OutSize[1], ap->OutSize[2]);
	}
	ap->ActiMat = (Mat*)malloc(ap->OutSize[0] * sizeof(Mat));
	ap->DeltaMat = (Mat*)malloc(ap->OutSize[0] * sizeof(Mat));
	for (i = 0; i < ap->OutSize[0]; ++i)
	{
		MatCreate(&ap->ActiMat[i], ap->OutSize[1], ap->OutSize[2]);
		MatCreate(&ap->DeltaMat[i], ap->OutSize[1], ap->OutSize[2]);
	}
	return ap;
}

int CreateNNMatSpace(CNN *cnn)
{
	int i;
	SpaceCreateInputLayer(&cnn->Layers[0]);
	for (i = 1; i < cnn->HiddenLayerNum + 2; ++i)
	{
		if (cnn->Layers[i].LayerType == 0)
		{
			SpaceCreateFullConnLayer(&cnn->Layers[i], cnn->Layers[i - 1].OutSize);
			continue;
		}
		if (cnn->Layers[i].LayerType == 1)
		{
			SpaceCreateConvLayer(&cnn->Layers[i], cnn->Layers[i - 1].OutSize);
			continue;
		}
		if (cnn->Layers[i].LayerType == 2)
		{
			SpaceCreateDeConvLayer(&cnn->Layers[i], cnn->Layers[i - 1].OutSize);
			continue;
		}
		if (cnn->Layers[i].LayerType == 3)
		{
			SpaceCreateMaxPoolLayer(&cnn->Layers[i], cnn->Layers[i - 1].OutSize);
			continue;
		}
		if (cnn->Layers[i].LayerType == 4)
		{
			SpaceCreateAvePoolLayer(&cnn->Layers[i], cnn->Layers[i - 1].OutSize);
			continue;
		}
	}
	return 0;
}

int CreateNNSpaceAndLoadinPara2Layer(CNN *cnn, Predefine pdf)
{
	cnn->Layers = SpaceCreateLayers(cnn);
	MatCreate(&cnn->OnehotMat, cnn->sampleCapacity, pdf.LabelNum);
	LoadinPara2Layers(cnn, pdf);
	CreateNNMatSpace(cnn);
	return 0;
}
